package com.ruoyi.project.applet.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.enums.PayStatus;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.wx.WXPayUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.applet.domain.*;
import com.ruoyi.project.applet.mapper.OrderMapper;
import com.ruoyi.project.applet.mapper.VipLevelMapper;
import com.ruoyi.project.applet.service.*;
import com.ruoyi.project.applet.util.AesUtil;
import com.ruoyi.project.applet.util.VechatPayV3Util;
import com.ruoyi.project.applet.util.WechatPayAuthUtil;
import com.ruoyi.project.pc.service.IAdvertisementService;
import com.ruoyi.project.system.domain.SysUserWx;
import com.ruoyi.project.system.service.ISysUserWxService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.http.*;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
import com.yungouos.pay.entity.RePayBiz;
import com.yungouos.pay.finance.Finance;
import okhttp3.OkHttpClient;
import org.apache.commons.collections4.FunctorException;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

import static com.wechat.pay.java.core.http.Constant.*;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_TIMESTAMP;

@Service
public class PayServiceImpl implements IPayService {

    private static final Logger logger = LoggerFactory.getLogger("PayServiceImpl");


    @Autowired
    IWallelogService logService;

    @Autowired
    IWalletService walletService;

    @Autowired
    IWallelogService wallelogService;

    @Autowired
    IOrderService orderService;

    @Autowired
    ISysUserWxService userWxService;

    @Autowired
    private RatioServiceImpl ratioService;

    @Autowired
    private OrderMapper orderMapper;

    @Value("${url.prefix}")
    private String urlPrefix;

    @Value("${wx.wxAppId}")
    private String appId;
    @Value("${wx.mchid}")
    private String mchid;
    @Value("${wx.mchkey}")
    private String mchkey;

    @Value("${wx.privateKeyPath}")
    public String privateKeyPath;
    /**
     * 商户证书序列号
     */
    @Value("${wx.merchantSerialNumber}")
    public String merchantSerialNumber;

    @Value("${wx.payNotifyUrl}")
    public String payNotifyUrl;
    /**
     * 退款结果回调url
     */
    @Value("${wx.takeNotifyUrl}")
    public String takeNotifyUrl;

    /**
     * 货币类型
     */
    @Value("${wx.currency}")
    public String currency;

    //    @Value("${environment.dev:false}")
    private static boolean isDev = false;


    @Autowired
    private VipServiceImpl vipService;

    @Autowired
    private VipLevelMapper vipLevelMapper;

    @Override
    public AjaxResult pay(SysUserWx sysUserWx) {
        /**
         * 创建订单
         */
        SysUserWx userWx = userWxService.selectSysUserWxById(sysUserWx.getUserId());
        Assert.notNull(userWx, "下单用户不存在");
        Order order = new Order();
        order.setStatus(PayStatus.NO_PAY.getName());
        order.setOpenId(sysUserWx.getOpenId());
        order.setGoodId(sysUserWx.getVipId());
        order.setPhone(userWx.getPhonenumber());
        String number = "SP" + DateUtils.getNowNanosecond();
        order.setNumber(number);
        String id = UUID.randomUUID().toString();
        order.setId(id);
        order.setPhone(userWx.getPhonenumber());

        Vip vip = vipService.selectVipById(sysUserWx.getVipId());

        order.setPayAmount(vip.getMoney());
        order.setOriginalMoney(vip.getOriginalMoney());
        order.setVipDay(vip.getDay());
        order.setGoodName(vip.getName());

        final String prepayId = getPrepayId(order, urlPrefix.trim() + "/back/payment");
        order.setPrepayId(prepayId);

        //设置分销人
        if (StringUtils.hasText(userWx.getParentId())) {
            SysUserWx firstParent = userWxService.selectSysUserWxByOpenId(userWx.getParentId());
            //当推荐人存在上级推荐人时，设置该推荐人为二级分销，否则设置为一级分销
            if (StringUtils.hasText(firstParent.getParentId())) {
                SysUserWx secondParent = userWxService.selectSysUserWxByOpenId(firstParent.getParentId());
                order.setFirstParent(secondParent.getOpenId());
                order.setSecondParent(firstParent.getOpenId());
            } else {
                order.setFirstParent(firstParent.getOpenId());
            }
        }

        orderService.insertOrder(order);

        Map<String, String> result = null;
        try {
            result = this.UnifiedOrder(prepayId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //回调
        //back(number);

        return AjaxResult.success(result);
    }

    @Override
    public AjaxResult v3Pay(SysUserWx sysUserWx) throws Exception {
        /**
         * 创建订单
         */
        SysUserWx userWx = userWxService.selectSysUserWxById(sysUserWx.getUserId());
        Assert.notNull(userWx, "下单用户不存在");
        Order order = new Order();
        order.setStatus(PayStatus.NO_PAY.getName());
        order.setOpenId(sysUserWx.getOpenId());
        order.setGoodId(sysUserWx.getVipId());
        order.setPhone(userWx.getPhonenumber());
        String number = "SP" + DateUtils.getNowNanosecond();
        order.setNumber(number);
        String id = UUID.randomUUID().toString();
        order.setId(id);
        order.setPhone(userWx.getPhonenumber());

        Vip vip = vipService.selectVipById(sysUserWx.getVipId());

        order.setPayAmount(vip.getMoney());
        order.setOriginalMoney(vip.getOriginalMoney());
        order.setVipDay(vip.getDay());
        order.setGoodName(vip.getName());

        // 1. 初始化配置
        RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(mchid)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(mchkey)
                .build();

        JsapiServiceExtension payService = new JsapiServiceExtension.Builder()
                .config(config)
                .signType("RSA") // 不填默认为RSA
                .build();

        PrepayRequest request = new PrepayRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        Amount amount = new Amount();
        amount.setTotal(Integer.valueOf(amount_fee(vip.getMoney())));
        amount.setCurrency(currency);
        request.setAmount(amount);
        request.setDescription("会员充值");
        request.setAppid(appId);
        request.setMchid(mchid);
        request.setNotifyUrl(payNotifyUrl);
        request.setOutTradeNo(number);
        // request.setSceneInfo(new SceneInfo());
        Payer payer = new Payer();
        payer.setOpenid(userWx.getOpenId());
        request.setPayer(payer);
        logger.info(request.toString());
        // 调用接口
        PrepayWithRequestPaymentResponse response = payService.prepayWithRequestPayment(request);
        logger.info(response.toString());

        Map<String, String> map = new HashMap<>();
        map.put("appId", response.getAppId());
        map.put("timeStamp", response.getTimeStamp());
        map.put("nonceStr", response.getNonceStr());
        map.put("package", response.getPackageVal());
        map.put("signType", response.getSignType());
        map.put("paySign", response.getPaySign());

        //设置分销人
        if (StringUtils.hasText(userWx.getParentId())) {
            SysUserWx firstParent = userWxService.selectSysUserWxByOpenId(userWx.getParentId());
            //当推荐人存在上级推荐人时，设置该推荐人为二级分销，否则设置为一级分销
            if (StringUtils.hasText(firstParent.getParentId())) {
                SysUserWx secondParent = userWxService.selectSysUserWxByOpenId(firstParent.getParentId());
                order.setFirstParent(secondParent.getOpenId());
                order.setSecondParent(firstParent.getOpenId());
            } else {
                order.setFirstParent(firstParent.getOpenId());
            }
        }
        order.setPrepayId(response.getPackageVal());
        orderService.insertOrder(order);

        return AjaxResult.success(map);
    }

    @Override
    public String backPayOrder(HttpServletRequest request, HttpServletResponse response) {
        RequestParam requestParam = buildRequestParam(request);
        // 1. 初始化配置
        RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(mchid)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(mchkey)
                .build();

        NotificationParser notificationParser = new NotificationParser(config);
        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
            if ("SUCCESS".equals(transaction.getTradeState().toString())) {
                logger.info("支付成功：" + transaction.getOutTradeNo());
                //处理支付成功业务逻辑
                String orderNumber = transaction.getOutTradeNo();
                Order order = orderService.selectOrderByOrderNumber(orderNumber);
                //将订单状态改为支付成功
                Date date = new Date();
                //会员设置到期时间
                int goodId = order.getGoodId();
                Vip vip = vipService.selectVipById(goodId);
                SysUserWx sysUserWx = userWxService.selectSysUserWxByOpenId(order.getOpenId());
                if (sysUserWx.getExpirationTime() == null) {
                    Date currentDate = new Date();
                    // 使用Calendar类来操作日期
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(currentDate);
                    calendar.add(Calendar.DAY_OF_MONTH, vip.getDay()); // 加上30天

                    // 获取新的日期
                    Date newDate = calendar.getTime();
                    sysUserWx.setExpirationTime(newDate);
                    logger.info("用户:"+sysUserWx.getUserId()+ "充值会员成功,充值金额" + order.getPayAmount() + "元,天数" + vip.getDay());
                } else {
                    Date expirationTime = sysUserWx.getExpirationTime();
                    logger.info("用户:"+sysUserWx.getUserId() +"当前会员到期时间:"+expirationTime);
                    // 使用Calendar类来操作日期
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(expirationTime);
                    calendar.add(Calendar.DAY_OF_MONTH, vip.getDay()); // 加上30天

                    // 获取新的日期
                    Date newDate = calendar.getTime();
                    sysUserWx.setExpirationTime(newDate);
                    logger.info("用户:"+sysUserWx.getUserId()+ "充值会员成功,充值金额" + order.getPayAmount() + "元,天数" + vip.getDay());
                }
                sysUserWx.setIsVip(Constants.IS_VIP);
                order.setStatus(PayStatus.PAY_SUCCESS.getName());
                order.setPayTime(date);
                orderService.updateOrder(order);

                //增加抽奖点数
                Wallet wallet = walletService.getWalletMoney(sysUserWx.getOpenId());
                wallet.setNumber(wallet.getNumber() + vip.getNumber());
                walletService.updateWallet(wallet);

                //设置会员等级
                String vipLevel = getVipLevel(sysUserWx);
                sysUserWx.setVipLevel(vipLevel);
                userWxService.updateSysUserWx(sysUserWx);

                //分销
                if (StringUtils.hasText(order.getFirstParent())) {
                    SysUserWx userWx = userWxService.selectSysUserWxByOpenId(order.getFirstParent());
                    //给一级分销人设置分销等级
                    String level = getVipLevel(userWx);
                    userWx.setVipLevel(level);
                    userWxService.updateSysUserWx(userWx);
                    //钱包余额加上分成
                    Wallet firstWaller = walletService.getWalletMoney(userWx.getOpenId());
                    List<Ratio> ratios = ratioService.selectRatioList(new Ratio());
                    String money = order.getPayAmount().multiply(ratios.get(0).getFirstRatio()).add(new BigDecimal(firstWaller.getMoney())).toString();
                    firstWaller.setMoney(money);
                    walletService.updateWallet(firstWaller);
                    //生成一条钱包记录
                    Wallelog wallelog = new Wallelog();
                    wallelog.setUserId(userWx.getOpenId());
                    wallelog.setAmount(order.getPayAmount().multiply(ratios.get(0).getFirstRatio()).toString());
                    wallelog.setType("0");
                    wallelog.setDescribe("一级分销提成");
                    wallelog.setOrderNumber(order.getNumber());
                    wallelog.setCreateTime(date);
                    logService.insertWallelog(wallelog);
                    logger.info("用户:"+userWx.getOpenId() +"一级分销成功,","金额"+wallelog.getAmount());
                }
                if (StringUtils.hasText(order.getSecondParent())) {
                    SysUserWx userWx = userWxService.selectSysUserWxByOpenId(order.getSecondParent());
                    //钱包余额加上分成
                    Wallet secondWaller = walletService.getWalletMoney(userWx.getOpenId());
                    List<Ratio> ratios = ratioService.selectRatioList(new Ratio());
                    String money = order.getPayAmount().multiply(ratios.get(0).getSecondRatio()).add(new BigDecimal(secondWaller.getMoney())).toString();
                    secondWaller.setMoney(money);
                    walletService.updateWallet(secondWaller);
                    //生成一条钱包记录
                    Wallelog wallelog = new Wallelog();
                    wallelog.setUserId(userWx.getOpenId());
                    wallelog.setAmount(order.getPayAmount().multiply(ratios.get(0).getSecondRatio()).toString());
                    wallelog.setType("0");
                    wallelog.setDescribe("二级分销提成");
                    wallelog.setOrderNumber(order.getNumber());
                    wallelog.setCreateTime(date);
                    logService.insertWallelog(wallelog);
                    logger.info("用户:"+userWx.getOpenId() +"二级分销成功,","金额"+wallelog.getAmount());
                }
                return "SUCCESS";
            }
            return null;
        } catch (ValidationException e) {
            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
            logger.error("sign verification failed", e);
            return null;
        }
    }

    public String getVipLevel(SysUserWx sysUserWx) {
        //查询自己归属于哪个等级
        List<VipLevel> vipLevels = vipLevelMapper.selectVipLevelList(new VipLevel());
        //查询一级分销订单是自己的有几个
        Order query = new Order();
        query.setFirstParent(sysUserWx.getOpenId());
        List<Order> orderList = orderService.selectOrderList(query);
        //根据userId去重
        if (!CollectionUtils.isEmpty(orderList)) {
            List<String> collect = orderList.stream().map(Order::getOpenId).distinct().collect(Collectors.toList());
            //获取分销人数
            int count = collect.size();
            for (VipLevel vipLevel : vipLevels) {
                if (count >= vipLevel.getUpNum()) {
                    if (vipLevel.getDownNum() != null) {
                        if (count <= vipLevel.getDownNum()) {
                            return vipLevel.getName();
                        }
                    } else {
                        return vipLevel.getName();
                    }
                }
            }
        }

        return vipLevels.get(0).getName();
    }


    /**
     * 构造 RequestParam
     *
     * @param request
     * @return
     */
    private RequestParam buildRequestParam(HttpServletRequest request) {
        String wechatPaySerial = request.getHeader(WECHAT_PAY_SERIAL);
        String wechatPayNonce = request.getHeader(WECHAT_PAY_NONCE);
        String wechatSignature = request.getHeader(WECHAT_PAY_SIGNATURE);
        String wechatTimestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        //读取请求体的信息
        String requestBody = "";
        try {
            requestBody = IoUtil.read(request.getReader());
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        return new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatPayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult takePay(String amount, String name, SysUserWx userWx) throws Exception {

        Wallet walletMoney = walletService.getWalletMoney(userWx.getOpenId());
        BigDecimal total = new BigDecimal(walletMoney.getMoney());
        BigDecimal amountBig = new BigDecimal(amount);
        if (total.compareTo(amountBig) < 0) {
            throw new FunctorException("金额不足");
        }

        walletMoney.setMoney(total.subtract(amountBig).stripTrailingZeros().toPlainString());
        walletService.updateWallet(walletMoney);

        Wallelog log = new Wallelog();
        log.setAmount(amount);
        log.setUserId(userWx.getOpenId());
        log.setPartnerTradeNo("TX" + DateUtils.getNowNanosecond());
        JSONObject withdra1w = initiateBatchTransfer(log, "");

        log.setType("1");
        log.setUserId(userWx.getOpenId());
        // 支出 0 未结算 1 结算成功
        log.setStatus("0");

        logService.insertWallelog(log);
        return new AjaxResult(200, "", withdra1w.getString("package_info"));
    }

    @Override
    public AjaxResult yunGouTakePay(String amount, String openId, SysUserWx userWx) throws Exception {

        Assert.hasText(amount, "提现金额不能为空");
        Assert.hasText(openId, "用户openId不能为空");
        Wallet walletMoney = walletService.getWalletMoney(userWx.getOpenId());
        String yunGoOpenId = walletMoney.getOpenId();
        if (!StringUtils.hasText(yunGoOpenId)) {
            walletMoney.setOpenId(openId);
            walletService.updateWallet(walletMoney);
            logger.info("用户:" + userWx.getOpenId() + ",授权第三方提现成功,openId:" + openId);
        }
        BigDecimal total = new BigDecimal(walletMoney.getMoney());
        BigDecimal amountBig = new BigDecimal(amount);
        if (total.compareTo(amountBig) < 0) {
            throw new FunctorException("用户钱包金额不足");
        }


        Wallelog log = new Wallelog();
        log.setAmount(amount);
        log.setUserId(userWx.getOpenId());
        log.setPartnerTradeNo("TX" + DateUtils.getNowNanosecond());
        //  JSONObject withdra1w = initiateBatchTransfer(log, "");

        //三方提现

        yunGou(openId, amount);

        //提现成功再修改钱包和生成提现记录
        walletMoney.setMoney(total.subtract(amountBig).stripTrailingZeros().toPlainString());
        walletService.updateWallet(walletMoney);

        log.setType("1");
        log.setUserId(userWx.getOpenId());
        log.setDescribe("提现");
        // 支出 0 未结算 1 结算成功
        log.setStatus("1");
        logService.insertWallelog(log);

        logger.info("用户:" + userWx.getOpenId() + ",提现成功,金:" + amount);
        return AjaxResult.success();
    }

    public void yunGou(String openId, String money1) {
        String merchant_id = "100306323";// YunGouOS商户ID 登录YunGouOS.com-》账户设置-》开发者身份-》账户商户号
        String key = "216F8AA81B094462B71B944A413A227D";// 商户密钥 登录YunGouOS.com-》账户设置-》开发者身份-》账户商户号 商户密钥
        String out_trade_no = System.currentTimeMillis() + "";
        String account = openId;
        String account_name = "";
        String money = money1;
        String desc = "申贷提现";
        String mch_id = null;
        String notify_url = null;

        // 微信转账
        RePayBiz rePayBiz = Finance.rePayWxPay(merchant_id, out_trade_no, account, account_name, money, desc, mch_id, notify_url, key);

    }


    public JSONObject initiateBatchTransfer(Wallelog wallelog, String name) {
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appId);
        params.put("out_bill_no", wallelog.getPartnerTradeNo());
        params.put("transfer_scene_id", "1000");
        params.put("openid", wallelog.getUserId());
//        params.put("user_name", name);
        params.put("transfer_amount", Long.parseLong(amount_fee(new BigDecimal(wallelog.getAmount()))));
        params.put("transfer_remark", "佣金提现");
        params.put("notify_url", takeNotifyUrl);

        Map<String, String> transfer_scene_report_info = new HashMap<>();
        transfer_scene_report_info.put("info_type", "活动名称");
        transfer_scene_report_info.put("info_content", "佣金提现");
        Map<String, String> transfer_scene_report_info1 = new HashMap<>();
        transfer_scene_report_info1.put("info_type", "奖励说明");
        transfer_scene_report_info1.put("info_content", "佣金提现");
        params.put("transfer_scene_report_infos", new ArrayList<Map<String, String>>() {{
            add(transfer_scene_report_info);
            add(transfer_scene_report_info1);
        }});


        // 1. 初始化配置
        Config config = new RSAAutoCertificateConfig.Builder()
                .merchantId(mchid)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(mchkey)
                .build();

        OkHttpClient okHttpClient = new OkHttpClient();
        HttpClient httpClient =
                new DefaultHttpClientBuilder().config(config).okHttpClient(okHttpClient).build();


        com.wechat.pay.java.core.http.HttpHeaders headers = new com.wechat.pay.java.core.http.HttpHeaders();
        headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
        headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
        headers.addHeader("Wechatpay-Serial", merchantSerialNumber);

        String s = JSONUtil.toJsonStr(params);

        JsonRequestBody build = new JsonRequestBody.Builder()
                .body(s)
                .build();
        com.wechat.pay.java.core.http.HttpRequest executeSendGetHttpRequest =
                new HttpRequest.Builder()
                        .httpMethod(com.wechat.pay.java.core.http.HttpMethod.POST)
                        .url("https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills")
                        .headers(headers)
                        .body(build)
                        .build();

        HttpResponse<JSONObject> execute = httpClient.execute(executeSendGetHttpRequest, JSONObject.class);

        JSONObject body = execute.getServiceResponse();
        logger.info("提现返参:{}", body);
        System.out.println();
        return body;

    }

    @Override
    public String refundPayOrder(HttpServletRequest request, HttpServletResponse response) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()))) {

            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            String notityXml = sb.toString();


            final JSONObject jsonObject = JSON.parseObject(notityXml);
            final JSONObject resource = jsonObject.getJSONObject("resource");

            String associated_data = resource.getString("associated_data");
            String ciphertext = resource.getString("ciphertext");
            String nonce = resource.getString("nonce");
            JSONObject json = new JSONObject();

            try {
                String decryptData = new AesUtil(mchkey.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
                json = JSON.parseObject(decryptData);
            } catch (Exception e) {
                logger.error("", e);
            }

            String returnCode = json.getString("state");
            String resXml = "";
            if ("SUCCESS".equals(returnCode)) {
                logger.info("TK:[{}]", json);

                String out_bill_no = json.getString("out_bill_no");
                //业务逻辑

                final Wallelog wallelog = logService.selectWallelogByTradeNo(out_bill_no);
                wallelog.setStatus("1");
                logService.updateWallelog(wallelog);

                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }

            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            return resXml;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private String getPrepayId(Order order, String notify_url) {
        try {
            String ipAddr = IpUtils.getIpAddr(ServletUtils.getRequest());

            String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            Random RANDOM = new SecureRandom();
            char[] nonceChars = new char[32];
            for (int index = 0; index < nonceChars.length; ++index) {
                nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
            }
            String nonce_str = new String(nonceChars);//随机字符串
            String body = "商品购买";

            String trade_type = "JSAPI";

            Map<String, String> map = new HashMap<>();
            map.put("appid", appId);
            map.put("mch_id", mchid);
            map.put("nonce_str", nonce_str);
            map.put("attach", order.getOpenId());
            map.put("body", body);
            map.put("out_trade_no", order.getNumber());
            map.put("total_fee", amount_fee(order.getPayAmount()));
            map.put("spbill_create_ip", ipAddr);
            map.put("trade_type", trade_type);
            map.put("notify_url", notify_url);
            map.put("openid", order.getOpenId());
            String sign = WXPayUtil.generateSignature(map, mchkey);
            map.put("sign", sign);
            // 获取公众号prepay_id的链接
            String prepayIdUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String xml = WXPayUtil.mapToXml(map);
            String post = WXPayUtil.doPost(prepayIdUrl, xml);
            Map<String, String> stringMap = WXPayUtil.xmlToMap(post);
            // 如果请求成功
            if (null != post) {
                return stringMap.get("prepay_id");
            } else {
                throw new FunctorException("未获取到prepay_id");
            }
        } catch (Exception e) {
            throw new FunctorException("未获取到prepay_id");
        }
    }

    public Map<String, String> UnifiedOrder(String prepayId) throws Exception {

        Date time = new Date();
        String timeStamp = String.valueOf(time.getTime() / 1000);

        String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random RANDOM = new SecureRandom();
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        String nonce = new String(nonceChars);

        String signType = "MD5";
        Map<String, String> map = new HashMap<>();
        map.put("appId", appId);
        map.put("timeStamp", timeStamp);
        map.put("nonceStr", nonce);
        map.put("package", "prepay_id=" + prepayId);
        map.put("signType", signType);
        String paySign = WXPayUtil.generateSignature(map, mchkey);
        map.put("paySign", paySign);
        return map;
    }

    public String amount_fee(BigDecimal cny) {
        BigDecimal b2 = new BigDecimal(100);
        return cny.multiply(b2).setScale(0, RoundingMode.DOWN).toString();
    }

    @Override
    public AjaxResult refund(String id, String money, String refundNumber) {
        Order order = orderMapper.selectOrderById(id);
        if (order == null) {
            throw new BaseException("订单不存在");
        }
        if (PayStatus.REFUND_SUCCESS.getName().equals(order.getStatus())) {
            throw new BaseException("订单已退款");
        }
        if (PayStatus.WAIT_REFUND.getName().equals(order.getStatus())) {
            throw new BaseException("订单正在退款中");
        }
        Map<String, String> map = new HashMap<>();
        //随机字符串
        String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random RANDOM = new SecureRandom();
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        String nonce_str = new String(nonceChars);

        String notify_url = urlPrefix.trim() + "/system/pay/refund/payment";

        if (!StringUtils.hasText(refundNumber)) {
            refundNumber = "TK" + DateUtils.getNowNanosecond();
        }


        map.put("appid", appId);
        map.put("mch_id", mchid);
        map.put("nonce_str", nonce_str);
        map.put("notify_url", notify_url);
        map.put("out_trade_no", order.getNumber());
        map.put("out_refund_no", refundNumber);
        map.put("total_fee", amount_fee(order.getPayAmount()));
        map.put("refund_fee", amount_fee(new BigDecimal(money)));
        String sign = null;
        try {
            sign = WXPayUtil.generateSignedXml(map, mchkey);
            String payRefundURL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            String resultXml = this.doRefund(payRefundURL, sign);
            Map<String, String> post = WXPayUtil.xmlToMap(resultXml);
            if (post.get("result_code").equals("SUCCESS") && post.get("return_code").equals("SUCCESS")) {
                //修改订单状态为退款中
                // order.setStatus(PayStatus.WAIT_REFUND.getName());
                // orderService.updateOrder(order);
                logger.info("申请退款成功:", order.getNumber());
                return AjaxResult.success("申请退款成功");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return AjaxResult.error("申请退款失败");
    }


    public String doRefund(String url, String data) throws Exception {

        //指定读取证书格式为PKCS12(注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的)
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        // 指定证书路径
        ClassPathResource classPathResource = new ClassPathResource("cert/apiclient_cert.p12");
        //读取本机存放的PKCS12证书文件
        InputStream instream = classPathResource.getInputStream();

        try {
            //指定PKCS12的密码(商户ID)
            keyStore.load(instream, mchid.toCharArray());
        } finally {
            instream.close();

        }

        SSLContext sslcontext = org.apache.http.conn.ssl.SSLContexts.custom().loadKeyMaterial(keyStore, mchid.toCharArray()).build();

        //指定TLS版本
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        //设置httpclient的SSLSocketFactory
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        try {
            HttpPost httpost = new HttpPost(url);// 设置响应头信息

            httpost.addHeader("Connection", "keep-alive");

            httpost.addHeader("Accept", "*/*");

            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

            httpost.addHeader("Host", "api.mch.weixin.qq.com");

            httpost.addHeader("X-Requested-With", "XMLHttpRequest");

            httpost.addHeader("Cache-Control", "max-age=0");

            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");

            httpost.setEntity(new StringEntity(data, "UTF-8"));

            CloseableHttpResponse response = httpclient.execute(httpost);

            try {
                HttpEntity entity = response.getEntity();

                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");

                EntityUtils.consume(entity);

                return jsonStr;

            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}
